package com.zjinyin.forum.service.impl;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: DELL
 * Date: 2023-08-09
 * Time: 14:30
 */

import com.zjinyin.forum.common.AppResult;
import com.zjinyin.forum.common.ResultCode;
import com.zjinyin.forum.dao.UserMapper;
import com.zjinyin.forum.exception.ApplicationException;
import com.zjinyin.forum.model.User;
import com.zjinyin.forum.service.IUserService;
import com.zjinyin.forum.utils.MD5Util;
import com.zjinyin.forum.utils.StringUtil;
import com.zjinyin.forum.utils.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

/**
 * 对普通用户与数据库交互接口功能的实现
 */
@Service
@Slf4j
public class UserServiceImpl implements IUserService {

    @Resource
    private UserMapper userMapper;

    /**
     * 创建一个普通用户
     *
     * @param user 用户信息
     */
    @Override
    public void createNormalUser(User user) {
        // 1. 对用户对象的数据进行校验
        if (user == null || StringUtil.isEmpty(user.getUsername())
                || StringUtil.isEmpty(user.getPassword()) || StringUtil.isEmpty(user.getNickname())
                || StringUtil.isEmpty(user.getSalt())) {
            // 1.1. 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());

            // 1.2 . 抛出统一异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }

        // 2. 查询用户名是否存在
        User existsUser = userMapper.selectByUserName(user.getUsername());

        // 2.1 对用户做出判断
        if (existsUser != null) {
            // 打印日志
            log.info(ResultCode.FAILED_USER_EXISTS.toString());

            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
        }

        // 3. 用户不存在, 创建用户
        // 3.1 设置默认值
        user.setGender((byte) 2);
        user.setArticleCount(0);
        user.setIsAdmin((byte) 0);
        user.setState((byte) 0);
        user.setDeleteState((byte) 0);
        // 设置当前日期
        Date date = new Date();
        user.setCreateTime(date);
        user.setUpdateTime(date);

        // 4. 写入数据库
        int row = userMapper.insertSelective(user);

        if (row != 1) {
            // 4.1 打印日志
            log.info(ResultCode.FAILED_CREATE.toString());

            // 4.2 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
        }

        // 打印成功插入数据库日志
        log.info("新增用户成功 : username = " + user.getUsername() + ".");
    }

    /**
     * 按照用户名查找用户
     *
     * @param username 用户名
     * @return 返回查找的指定用户
     */
    @Override
    public User selectByUserName(String username) {
        // 1. 参数校验
        if (StringUtil.isEmpty(username)) {
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());

            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }

        return userMapper.selectByUserName(username);
    }

    /**
     * 登录方法
     *
     * @param username 用户名
     * @param password 用户密码
     * @return 返回指定的登录用户
     */
    @Override
    public User login(String username, String password) {

        // 1. 参数校验
        if (StringUtil.isEmpty(username) || StringUtil.isEmpty(password)) {
            log.warn(ResultCode.FAILED_LOGIN.toString());

            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }

        // 2. 查询当前用户信息
        User user = selectByUserName(username);

        // 3. 对查询 user 进行判断
        if (user == null) {
            // 不存在这个用户名 - 提示账号或密码错误
            log.warn(ResultCode.FAILED_LOGIN.toString() + ", username : " + username);

            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }

        // 4. 判断密码
        // 4.1 获取盐值并和明文密码加密
        String salt = user.getSalt();
        String ciphertext = MD5Util.md5(password, salt);

        // 4.2 检验密码
        if (!ciphertext.equals(user.getPassword())) {
            log.warn(ResultCode.FAILED_LOGIN.toString() + ", " + username + "的密码错误 ");

            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }

        log.info("用户 " + username + " 登陆成功");
        return user;
    }

    /**
     * 根据 id 查询指定用户
     *
     * @param id 用户 id 编号
     * @return 返回查询的指定用户
     */
    @Override
    public User selectByPrimaryKey(Long id) {

        // 1. 校验参数
        if (id == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }

        // 2. 根据 id 查询用户
        User user = userMapper.selectByPrimaryKey(id);

        // 3. 校验结果
        if (user == null) {
            // 打印日志
            log.warn("id :" + id + " " + ResultCode.FAILED_USER_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED + " 当前用户状态异常"));
        }
        log.info("查询到 user id=" + id + " 的用户");

        return user;
    }

    /**
     * 根据 id 编号查询指定用户下的文章数 + 1
     *
     * @param id 用户 id 编号
     */
    @Override
    public void increaseOneArticleCountById(Long id) {
        // 1. 参数校验
        if (id == null || id <= 0) {
            log.warn(ResultCode.FAILED_USER_COUNT_ARTICLE.toString());
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_COUNT_ARTICLE));
        }

        // 2. 查询指定 id 编号的用户
        User user = userMapper.selectByPrimaryKey(id);
        if (user == null) {
            log.warn("user id : " + id + " " + ResultCode.FAILED_USER_NOT_EXISTS.toString());
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }

        // 4. 更新这个指定 id 版块下的文章数
        User updateUser = new User();
        // 虽然是动态更新 user 对象, 但是 id 是自增主键需要传, 动态 SQL 未对 id 做出判断
        updateUser.setId(user.getId());
        updateUser.setArticleCount(user.getArticleCount() + 1);
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        if (row != 1) {
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString() + " , 受影响行数 > 1 错误");
        }
        log.info("userId : " + id + ", 发表文章数 + 1 更新成功 ");
    }


    /**
     * 删除指定用户下的帖子, 帖子总数 - 1
     *
     * @param id 用户 id
     */
    @Override
    public void deleteOneArticleCountById(Long id) {
        // 1. 参数校验
        if (id == null || id <= 0) {
            log.warn(ResultCode.FAILED_USER_COUNT_ARTICLE.toString());
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_COUNT_ARTICLE));
        }

        // 2. 获取指定
        User user = userMapper.selectByPrimaryKey(id);

        // 3. 检验版块
        if (user == null) {
            log.warn("userId : " + id + " " + ResultCode.FAILED_USER_NOT_EXISTS);
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }

        // 4. 构建新对象
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setArticleCount(user.getArticleCount() - 1);

        // 5. 处理特殊情况
        if (updateUser.getArticleCount() < 0) {
            updateUser.setArticleCount(0);
        }

        // 5. 写回数据库
        int row = userMapper.updateByPrimaryKeySelective(updateUser);

        // 6. 检验结果
        if (row != 1) {
            log.warn(ResultCode.FAILED + " , 受影响行数不为 1 错误");
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED) + " , 受影响行数不为 1 错误");
        }

        log.info("用户帖子数目减 1 成功");
    }


    /**
     * 用户中心的修改功能
     *
     * @param user 当前登录用户
     */
    @Override
    public void modifyUserInfo(User user) {

        // 1. 参数检验
        if (user == null || user.getId() == null || user.getId() <= 0) {
            log.warn("修改用户的参数  " + ResultCode.FAILED_PARAMS_VALIDATE);
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }

        // 2. 获取这个用户的 id 查询数据库是否存在这个用户
        User existsUser = userMapper.selectByPrimaryKey(user.getId());

        // 3. 检验 user1
        if (existsUser == null) {
            log.warn("user : " + ResultCode.FAILED_USER_NOT_EXISTS);
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }

        // 4. 检验 user1 中传入的修改内容 -- 用户名 昵称 邮箱 手机号 修改密码 等字段不一定传入那个, 需要检验
        boolean checkAttr = false; // 为 true 表明检验的某个字段检验为通过

        User updateUser = new User();
        updateUser.setId(user.getId());
        // 检查是否更新用户名 -- 传入了名字并且传入的名字和当前的名字不相同
        if (!StringUtil.isEmpty(user.getUsername()) && !user.getUsername().equals(existsUser.getUsername())) {
            User checkUser = userMapper.selectByUserName(user.getUsername());
            if (checkUser != null) {
                // 已经存在这个用户名
                log.warn("username : " + user.getUsername() + " " + ResultCode.FAILED_USER_EXISTS);
                throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
            }
            // 不存在表示需要更新用户名
            updateUser.setUsername(user.getUsername());
            // 更新标志位
            checkAttr = true;
        }

        // 检验昵称
        if (!StringUtil.isEmpty(user.getNickname()) && !user.getNickname().equals(existsUser.getNickname())) {
            // 更新昵称
            updateUser.setNickname(user.getNickname());
            // 更新标志位
            checkAttr = true;
        }

        // 检验性别
        if (user.getGender() != null && !user.getGender().equals(existsUser.getGender())) {
            // 更新性别
            updateUser.setGender(user.getGender());
            // 更新标志位
            checkAttr = true;
        }

        // 检验 Email
        if (!StringUtil.isEmpty(user.getEmail()) && !user.getEmail().equals(existsUser.getEmail())) {
            updateUser.setEmail(user.getEmail());
            checkAttr = true;
        }

        // 检验手机号
        if (!StringUtil.isEmpty(user.getPhoneNum()) && !user.getPhoneNum().equals(existsUser.getPhoneNum())) {
            updateUser.setPhoneNum(user.getPhoneNum());
            checkAttr = true;
        }

        // 检验个人简介
        if (!StringUtil.isEmpty(user.getRemark()) && !user.getRemark().equals(existsUser.getRemark())) {
            updateUser.setRemark(user.getRemark());
            checkAttr = true;
        }
        // 5. 根据标志位判断是否执行更新操作
        if (!checkAttr) {
            // 说明没有任何一个字段需要更新
            log.warn("没有任何字段需要更新 : " + ResultCode.FAILED_PARAMS_VALIDATE);
            throw new ApplicationException(AppResult.failed("请输入修改的内容"));
        }

        // 有其中一项或多项(修改密码)需要更新
        int row = userMapper.updateByPrimaryKeySelective(updateUser);

        if (row != 1) {
            log.warn(ResultCode.FAILED + " , 受影响行数不为 1 错误");
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED) + " , 受影响行数不为 1 错误");
        }

        log.info("修改个人信息成功 ");

    }


    /**
     * 个人中心修改密码
     *
     * @param userId      用户 id
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     */
    @Override
    public void modifyPassword(Long userId, String oldPassword, String newPassword) {

        // 1. 参数校验
        if (userId == null || userId <= 0
                || StringUtil.isEmpty(oldPassword) || StringUtil.isEmpty(newPassword)) {

            log.warn("userId : " + userId + " " + ResultCode.FAILED_PARAMS_VALIDATE.toString());
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }

        // 2. 查询要修改的用户
        User user = userMapper.selectByPrimaryKey(userId);

        if (user == null || user.getDeleteState() == 1) {
            log.warn("userId : " + userId + " " + ResultCode.FAILED_USER_NOT_EXISTS);
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }

        // 3. 校验旧密码是否正确

        if (!MD5Util.md5(oldPassword, user.getSalt()).equals(user.getPassword())) {
            log.warn("原密码错误, 请重新输入");
            throw new ApplicationException(" 原密码错误, 请重新输入");
        }

        // 4. 对新密码重新加盐
        String salt = UUIDUtil.UUID_32();

        String encryptPassword = MD5Util.md5(newPassword, salt);

        // 5. 更新密码
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setSalt(salt);
        updateUser.setPassword(encryptPassword);
        updateUser.setUpdateTime(new Date());

        // 6. 写入数据库
        int row = userMapper.updateByPrimaryKeySelective(updateUser);

        if (row != 1) {
            log.warn(ResultCode.FAILED + " , 受影响行数不为 1 错误");
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED) + " , 受影响行数不为 1 错误");
        }

        // 打印日志
        log.info("userId : " + userId + " 密码修改成功");
    }


    @Override
    public void upLoad(String image_path, Long id) {
        // 1. 参数校验
        if (StringUtil.isEmpty(image_path)) {
            log.warn("图片上传失败 : " + ResultCode.FAILED_PARAMS_VALIDATE);
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }

        if (id == null || id <= 0) {
            log.warn("userId : " + id + " " + ResultCode.FAILED_PARAMS_VALIDATE);
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }

        // 2. 构建更新对象
        User updateUser = new User();
        updateUser.setId(id);
        updateUser.setAvatarUrl(image_path);

        // 3. 更新对象写回数据库
        int row = userMapper.updateByPrimaryKeySelective(updateUser);

        if (row != 1) {
            log.warn(ResultCode.FAILED + " , 受影响行数不为 1 错误");
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED) + " , 受影响行数不为 1 错误");
        }

        log.info("图片上传成功");
    }
}
